using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace BlobNet.TestsCommon.DataProviderHelpers.Base
{
    /// <summary>
    /// Base class for the data providers test helpers
    /// </summary>
    public abstract class DataProviderTestHelper
    {
        protected abstract string GetConnectionString();

        protected static string GetBlobDomainObjectName(Guid blobDomainId, string genericName)
        {
            return string.Concat(GetBlobDomainPrefix(blobDomainId), genericName);
        }

        private static string GetBlobDomainPrefix(Guid blobDomainId)
        {
            return "X" + blobDomainId.ToString().Replace('-', '_');
        }

        protected static object ReadBytes(IDataReader reader, int columnPos)
        {
            return ReadBytes(reader, columnPos, false);
        }

        protected static object ReadBytes(IDataReader reader, int columnPos, bool read)
            //read to specify if it has to read from the reader
        {
            object result = null;
            const int bufferSize = 1024;
            var outbyte = new byte[bufferSize];
            long startIndex = 0;

            if (!read || reader.Read())
            {
                using (var memStream = new MemoryStream())
                {
                    using (var bw = new BinaryWriter(memStream))
                    {
                        long retval;
                        try
                        {
                            retval = reader.GetBytes(columnPos, startIndex, outbyte, 0, bufferSize);
                        }
                        catch
                        {
                            //TODO: ELIMINAR EL CONTROL CON LA EXCEPCION
                            return null;
                        }

                        while (retval == bufferSize)
                        {
                            bw.Write(outbyte);
                            bw.Flush();

                            startIndex += bufferSize;
                            retval = reader.GetBytes(columnPos, startIndex, outbyte, 0, bufferSize);
                        }

                        bw.Write(outbyte, 0, (int)retval);
                        bw.Flush();


                        var bf = new BinaryFormatter();
                        memStream.Position = 0;
                        result = bf.Deserialize(memStream);
                    }
                }
            }

            return result;
        }

        protected static byte[] GetObjectBytes(object value)
        {
            byte[] result;
            using (var memStream = new MemoryStream())
            {
                var bf = new BinaryFormatter();
                bf.Serialize(memStream, value);
                result = memStream.ToArray();
            }
            return result;
        }

        public abstract Dictionary<string, object> GetEntitiesStatusRow(Guid domainId, Guid entityId,
                                                                        string propertyName);

        public abstract Dictionary<string, object> GetListEntitiesRow(Guid domainId, Guid collectionId, int position);

        public abstract void AddEntitiesStatusRow(Guid domainId, Guid ownerId, string propertyName, string valueType,string fullyQualifiedName,
                                                  object value);

        public abstract void AddListEntitiesRow(Guid domainId, Guid collectionId,
                                                string fullyQualifiedType, int position, object value);

        public abstract void RemoveListEntitiesRow(Guid domainId, Guid collectionId, int position);
        public abstract int CountEntitiesStatusRows(Guid domainId, Guid ownerId);

        public abstract int CountListEntitiesRows(Guid domainId, Guid collectionId);
        public abstract bool TableExists(Guid blobDomainId, string tableName); //This might not be a self describing name for this case
        public abstract void ClearTable(Guid blobDomainId, string tableName);
        protected abstract int ExecuteScalar(Guid domainId, string commandText);
    }
}